package com.pan.exe.factory;

import com.pan.base.ReflectUtil;
import com.pan.config.ApplicationConfig;
import com.pan.entity.ExecutiveInfo;
import com.pan.exe.Executive;
import com.pan.exe.impl.Anby4A;
import com.pan.script.ScriptTranslators;
import com.pan.script.util.ScriptUtil;

import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Arrays;

public class CommonExecutiveFactory implements ExecutiveFactory {

    private ScriptTranslators scriptTranslators;
    private ScriptUtil scriptUtil = ScriptUtil.INSTANCE;

    public CommonExecutiveFactory() {
        String scriptTranslatorName = ApplicationConfig.INSTANCE.getScriptTranslatorName();
        this.scriptTranslators = ReflectUtil.INSTANCE.newInstance(scriptTranslatorName);
    }

    @Override
    public Executive create(ExecutiveInfo info) {
        if (info.getType().equals("script")) {
            return createScript(info.getName());
        } else if (info.getType().equals("class")) {
            return createClass(info.getName());
        } else {
            throw new RuntimeException("Executive Type Error: not know this type of executive: " + info);
        }
    }

    private Executive createScript(String fileName) {
        InputStream scriptInputStream = scriptUtil.getScriptInputStream(fileName);
        Executive executive = scriptTranslators.to(scriptInputStream);
        return executive;
    }

    private Executive createClass(String className) {
        Executive executive = null;

        try {
            Class<?> executiveClass = Class.forName(className);
            if (Arrays.stream(executiveClass.getGenericInterfaces())
                    .filter(type->type.getTypeName().equals("com.pan.exe.Executive"))
                    .findFirst().isEmpty()){
                throw new RuntimeException("Not Executive Class Error: "+ className);
            }
            Constructor<?> constructor = executiveClass.getConstructor();
            Object o = constructor.newInstance();
            executive = (Executive) o;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return executive;
    }


}
